package jmine.tec.rtm.impl.web.pages.diagnosticador;

import static jmine.tec.web.wicket.spring.SpringBeanReference.forName;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jmine.tec.utils.MutableTuple;
import jmine.tec.web.pages.HelpTextMessages;
import jmine.tec.web.wicket.BeanReference;
import jmine.tec.web.wicket.component.button.ActionSubmitLink;
import jmine.tec.web.wicket.exception.ExceptionHandler;
import jmine.tec.web.wicket.pages.Template;

import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.target.resource.ResourceStreamRequestTarget;
import org.apache.wicket.spring.injection.annot.SpringBean;

import bancosys.tec.exception.MessageCreator;
import bancosys.tec.rtm.diagnostician.Diagnostician;
import bancosys.tec.rtm.diagnostician.DiagnosticianCase;
import bancosys.tec.rtm.impl.RtmController;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;

/**
 * Tela de consulta e geração de diagnosticos.
 * 
 * @author Rafael Volpato
 * @date May 31, 2011
 */
@Secure(id = "URL_REPORT_DIAGNOSTICADOR", permissionType = UrlPermission.class)
public class ConsultaDiagnosticador extends Template {

    private BeanReference<ExceptionHandler> exceptionHandler = forName("wicketExceptionHandler");

    @SpringBean(name = "diagnosticianCase")
    private DiagnosticianCase diagnosticianCase;

    @SpringBean
    private RtmController controller;

    private transient List<MutableTuple<String, Boolean>> diagnosticadores;

    private transient Map<String, Diagnostician> diagnosticianMap;

    private Form<Void> form;

    private Boolean selecionaTodos;

    /**
     * Construtor.
     */
    public ConsultaDiagnosticador() {
        super();
        this.initForm();
    }

    /**
     * Inicializa o form.
     */
    private void initForm() {
        this.form = new Form<Void>("mainForm");
        this.add(new FeedbackPanel("feedback"));

        WebMarkupContainer containerLista = new WebMarkupContainer("containerLista");
        containerLista.setOutputMarkupId(true);
        AjaxCheckBox chSelecionaTodos = new AjaxCheckBox("selecionaTodos", new PropertyModel<Boolean>(this, "selecionaTodos")) {
            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                for (MutableTuple<String, Boolean> tup : ConsultaDiagnosticador.this.getDiagnosticadores()) {
                    if (ConsultaDiagnosticador.this.selecionaTodos) {
                        tup.setTail(true);
                    } else {
                        tup.setTail(false);
                    }
                }
                target.addComponent(ConsultaDiagnosticador.this.form.get("containerLista"));
            }
        };
        containerLista.add(chSelecionaTodos);
        final ListView<MutableTuple<String, Boolean>> diagnosticadoresView =
                new ListView<MutableTuple<String, Boolean>>("diagnosticadores", new PropertyModel<List<MutableTuple<String, Boolean>>>(
                        this, "diagnosticadores")) {
                    @Override
                    protected void populateItem(ListItem<MutableTuple<String, Boolean>> item) {
                        final MutableTuple<String, Boolean> tupla = item.getModelObject();
                        item.add(new CheckBox("listSelecaoDiagnosticador", new PropertyModel<Boolean>(tupla, "tail")));
                        item.add(new Label("nomeDiagnosticador", tupla.getHead()));
                    }
                };
        containerLista.add(diagnosticadoresView);
        this.form.add(containerLista);

        SubmitLink linkExecutarDiagnosticadores = new ActionSubmitLink("btnDiagnosticador") {
            @Override
            public void onAction() {
                List<Diagnostician> diagnosticadoresSelecionados = new ArrayList<Diagnostician>();
                for (MutableTuple<String, Boolean> tup : ConsultaDiagnosticador.this.getDiagnosticadores()) {
                    if (tup.getTail()) {
                        diagnosticadoresSelecionados.add(ConsultaDiagnosticador.this.getDiagnostician(tup.getHead()));
                    }
                }

                if (diagnosticadoresSelecionados.isEmpty()) {
                    this.error("Selecione pelo menos um diagnóstico para ser gerado");
                    return;
                } else {
                    ResourceStreamRequestTarget target =
                            new ResourceStreamRequestTarget(new DiagnosticadorResourceStream(diagnosticadoresSelecionados,
                                    ConsultaDiagnosticador.this.controller));
                    target.setFileName("diagnosticador.txt");
                    RequestCycle.get().setRequestTarget(target);
                }
            }
        };

        this.form.add(linkExecutarDiagnosticadores);

        this.add(this.form);
    }

    /**
     * Returns the diagnostician with the given name
     * 
     * @param head String
     * @return {@link Diagnostician}
     */
    private Diagnostician getDiagnostician(String head) {
        return this.getDiagnosticianMap().get(head);
    }

    /**
     * Comparador de diagnosticos para auxiliar na comparação.
     * 
     * @author Rafael Volpato
     * @date May 31, 2011
     */
    private static final class ComparadorDiagnosticians implements Comparator<Diagnostician> {

        /**
         * {@inheritDoc}
         */
        public int compare(Diagnostician o1, Diagnostician o2) {
            return new CompareToBuilder().append(o1.getName(), o2.getName()).toComparison();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return HelpTextMessages.CONSULTA_DIAGNOSTICADOR;
    }

    /**
     * @return the diagnosticadores
     */
    public List<MutableTuple<String, Boolean>> getDiagnosticadores() {
        if (this.diagnosticadores == null) {
            try {
                this.diagnosticadores = new ArrayList<MutableTuple<String, Boolean>>();
                List<? extends Diagnostician> availableDiagnosticians = this.diagnosticianCase.getDiagnosticiansListOfSystemInDebugMode();
                Collections.sort(availableDiagnosticians, new ComparadorDiagnosticians());
                for (Diagnostician diagnostician : availableDiagnosticians) {
                    this.diagnosticadores.add(new MutableTuple<String, Boolean>(diagnostician.getName(), Boolean.FALSE));
                }
            } catch (Exception e) {
                this.exceptionHandler.get().handle(e);
            }
        }
        return this.diagnosticadores;
    }

    /**
     * @return the diagnosticianMap
     */
    public Map<String, Diagnostician> getDiagnosticianMap() {
        if (this.diagnosticianMap == null) {
            try {
                List<? extends Diagnostician> availableDiagnosticians = this.diagnosticianCase.getDiagnosticiansListOfSystemInDebugMode();
                this.diagnosticianMap = new HashMap<String, Diagnostician>(availableDiagnosticians.size());
                for (Diagnostician diagnostician : availableDiagnosticians) {
                    this.diagnosticianMap.put(diagnostician.getName(), diagnostician);
                }
            } catch (Exception e) {
                this.exceptionHandler.get().handle(e);
            }
        }
        return this.diagnosticianMap;
    }

}
